﻿#region Namespace References

using System;
using System.Reflection;
using DynConDevCorp.OpenArch.SmartData.Interfaces.MetaData;

#endregion

namespace DynConDevCorp.OpenArch.SmartData.Core.Metadata
{
    internal class SmartMetaEvent : ISmartMetaEvent
    {
        #region Constructors

        public SmartMetaEvent(Type sourceType, String sourceEventName)
        {
            EventSourceType = sourceType;
            EventName = sourceEventName;
            EventInfo = sourceType.GetEvent(sourceEventName);
            if (EventInfo != null)
            {
                EventAddMethodInfo = EventInfo.GetAddMethod();
                EventHandlerType = EventInfo.EventHandlerType;
            }
        }

        #endregion

        #region ISmartMetaEvent Members

        public void Wire(Object sourceInstance, Object targetInstance, String targetMethodName)
        {
            Type targetType = targetInstance.GetType();
            const BindingFlags flags =
                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
            MethodInfo targetMI = targetType.GetMethod(targetMethodName, flags);
            if (targetMI != null)
            {
                Type targetMIArgType = targetMI.GetParameters()[1].ParameterType;
                Type baseEventHandlerType = typeof (EventHandler<>);
                Type desiredEventHandlerType = baseEventHandlerType.MakeGenericType(new[] {targetMIArgType});
                Type eventArgType = EventHandlerType.GetGenericArguments()[0];
                //Type eventArgSpecialization = eventArgType.GetGenericArguments()[0];
                Type actualEventHandlerType = EventInfo.EventHandlerType;
                //bool handlerTypeMatch = desiredEventHandlerType == actualEventHandlerType;
                //bool argTypeMatch = targetMIArgType == eventArgType;


                if (true)
                {
                    Object targetMethodDelegate = Delegate.CreateDelegate(
                        actualEventHandlerType, /* desiredEventHandlerType,  */ /* EventHandlerType, */
                        targetInstance,
                        targetMI,
                        true);

                    EventAddMethodInfo.Invoke(sourceInstance, new[] {targetMethodDelegate});
                }
            }
        }

        #endregion

        #region Public Instance Properties

        public MethodInfo EventAddMethodInfo { get; private set; }
        public Type EventHandlerType { get; private set; }
        public EventInfo EventInfo { get; private set; }
        public String EventName { get; private set; }
        public Type EventSourceType { get; private set; }

        #endregion
    }
}